--[[
	This file is part of FlexBar3.

	FlexBar3 is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	FlexBar3 is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with FlexBar3.  If not, see <http://www.gnu.org/licenses/>.
]]

local Button = FlexBar3:GetModule("Button");
local SecureStateDriverFrame = Button.SecureStateDriverFrame;
local KeyBindings = Button:NewButtonClass("KeyBindings", 1);

-- Code taken from Ace2
local function ValidateBinding(text)
	if(text == nil or text == "NONE")then
		return nil
	end
	text = text:upper()
	local shift, ctrl, alt
	local modifier
	while true do
		if text == "-" then
			break
		end
		modifier, text = strsplit('-', text, 2)
		if text then
			if modifier ~= "SHIFT" and modifier ~= "CTRL" and modifier ~= "ALT" then
				return false
			end
			if modifier == "SHIFT" then
				if shift then
					return false
				end
				shift = true
			end
			if modifier == "CTRL" then
				if ctrl then
					return false
				end
				ctrl = true
			end
			if modifier == "ALT" then
				if alt then
					return false
				end
				alt = true
			end
		else
			text = modifier
			break
		end
	end
	if not text:find("^F%d+$") and text ~= "CAPSLOCK" and text:len() ~= 1 and (text:byte() < 128 or text:len() > 4) and not _G["KEY_" .. text] then
		return false
	end
	local s = text
	if shift then
		s = "SHIFT-" .. s
	end
	if ctrl then
		s = "CTRL-" .. s
	end
	if alt then
		s = "ALT-" .. s
	end
	return s
end

function KeyBindings:LoadSettings()
	self:ApplyBindings();
end

function KeyBindings:Enable()
	self.CurrentBindings = {};
	self:RegisterCallback("StatesUpdated", self.ApplyBindings);
end

function KeyBindings:Disable()
	self:UnregisterCallback("StatesUpdated", self.ApplyBindings);
end

local BindingsCache = {};

function KeyBindings:AddBinding(Binding)
	Binding = Binding:upper();
	local BoundButton = BindingsCache[Binding];
	-- Already set, don't bother
	if(BoundButton == self) then return false; end
	if(BoundButton) then
		BoundButton:RemoveBinding(Binding);
	end
	if(ValidateBinding(Binding)) then
		SetOverrideBindingClick(self.Frame, nil, Binding, self.Frame:GetName());
		tinsert(self.CurrentBindings, Binding);
		BindingsCache[Binding] = self;
		return true;
	else
		return false;
	end
end

function KeyBindings:RemoveBinding(Binding)
	Binding = Binding:upper();
	local BoundButton = BindingsCache[Binding];
	if(BoundButton ~= self) then return false; end
	BindingsCache[Binding] = nil;
	ClearOverrideBindings(self.Frame);
	for CurrentBinding in pairs(BindingsCache) do
		if(CurrentBinding == Binding) then
			self.CurrentBindings[Binding] = nil;
		else
			SetOverrideBindingClick(self.Frame, nil, CurrentBinding, self.Frame:GetName());
		end
	end
	return true;
end

function KeyBindings:GetBindings(StateModifier)
	if(not StateModifier) then StateModifier = "DefaultState"; end
	return self.StateDB[StateModifier].BindingSet;
end

function KeyBindings:ApplyBindings()
	local StateList = self.ActiveStateList;
	for i = 1, #StateList do
		local CurrentState = StateList[i];
		local CurrentStateDB = self.StateDB["*%s" .. CurrentState];
		local BindingSet = CurrentStateDB.BindingSet;
		if(BindingSet) then
			self:SetStateAttribute(CurrentState, "statebindings", CurrentState);
			self:SetAttribute(("bindings-%s"):format(CurrentState), BindingSet:concat(","));
			for i = 1, #BindingSet do
				self:AddBinding(BindingSet[i]);
			end
		end
	end
end
